package my.mark.mybaibaoxiang.juc.biji01.jmm;

/**
 * volatile禁止指令重排优化
 *
 * 双重检查锁定模式：
 * 双重检查锁定模式（也被称为"双重检查加锁优化"，"锁暗示"（Lock hint）) 是一种软件设计模式用来减少并发系统中竞争和同步的开销。
 * 双重检查锁定模式首先验证锁定条件(第一次检查)，只有通过锁定条件验证才真正的进行加锁逻辑并再次验证条件(第二次检查)。
 * 该模式在某些语言在某些硬件平台的实现可能是不安全的。
 * 它通常用于减少加锁开销，尤其是为多线程环境中的单例模式实现“惰性初始化”。惰性初始化的意思是直到第一次访问时才初始化它的值。
 */
public class Singleton {

    private Singleton() {
    }

    /**
     * 查看汇编指令（需安装Hsdis，工程下有。）
     * -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly -Xcomp
     */
    private volatile static Singleton myinstance;//TODO 加volatile防止下面对象初始化时产生指令重排。

    /**
     * TODO 超高并发下的单例一定要像下面这样加双重锁
     */
    public static Singleton getInstance() {
        if (myinstance == null) {
            synchronized (Singleton.class) {//synchronized不保证代码块里不发生指令重排。
                if (myinstance == null) {
                    /**
                     * TODO 对象创建过程，本质可以分为三步:
                     * 1、申请内存空间address=allocate。2、实例化对象instance(Object)，向内存填充对象数据。3、将内存空间地址指向myinstance变量引用myinstance=address。
                     * 三步没法保证原子性，也有可能发生指令重排。
                     * 比方2和3颠倒，高并发下线程1执行了3，还没执行2，
                     * TODO 此时myinstance有地址指向已经不为null，但里面没值。这时候再来请求，判断不为null直接返回了，则return之后操作里面便会空指针。
                     */
                    myinstance = new Singleton();
                    //对象延迟初始化
                    //
                }
            }
        }
        return myinstance;
    }

    public static void main(String[] args) {
        Singleton.getInstance();
    }
}
